# Moths - an environment for mathy calculations
# Copyright (C) 2006 Mike Sutjipto
# Licensed under the GPL

module Moths
  
  # One of the 'irreducable' types of expressions
  # i.e. evaluation returns back the same thing
  # Represents a matrix and the various operations that may be performed
  # on it.  This is also the generalization of vectors, so there's no need
  # for a separate Vector class
  #
  # TODO eventually matrices will need to have a more efficient representation.
  #      This may manifest itself in the form of some crazy ass shit
  #
  class Matrix < Expression
    @matrix
    @dim

    def initialize(matrix)
      @matrix = matrix
    end

    # Adds a row to the bottom of the matrix
    #
    def add_row(row)
    end

    # Returns whatever's at the ith row and jth col
    #
    def pos(i, j)
      return @matrix[i][j]
    end

    # Iterates through each position in the matrix
    # Takes in a code block and passes to it three things:
    # (1) the current element, (2) the row, and (3) the column
    #
    def map_each_pos
    end
    
    # The same as map_each_pos, only it doesn't include the row
    # or column
    #
    def map
    end
    
    # Returns the inverse of the matrix
    #
    def inverse
      return self
    end

    def +(r)
      case r
        when Matrix
          if self.dim != r.dim then
            raise MothsError, 'Undefined addition: matrices have different dim'
          end

          return self.map_each_pos { |e, i, j| e + r.pos(i, j) }

        when Number
          return self.map { |e| e + r }

        else
          raise MothsError, 'Addition undefined for these types'
      end
    end

    def -(r)
      case r
        when Matrix
          if self.dim != r.dim then
            raise MothsError, 'Undefined subtraction: matrices have different dim'
          end

          return self.map_each_pos { |e, i, j| e - r.pos(i, j) }

        when Number
          return self.map { |e| e - r }

        else
          raise MothsError, 'Subtraction undefined for these types'
      end
    end

    def *(r)
      case r
        when Matrix
          if self.dim != r.dim then
            raise MothsError, 'Undefined multiplication: matrices have different dim'
          end
          
          # TODO do it

        when Number
          return self.map { |e| e * r }

        else
          raise MothsError, 'Multiplication undefined for these types'
      end
    end

    def /(r)
      case r
        when Matrix
          return self * r.inverse

        when Number
          return self.map { |e| e / r }

        else
          raise MothsError, 'Division undefined for these types'
      end
    end

    def **(r)
      case r
        when Matrix
          raise MothsError, 'Exponentiation undefined for these types'
          
        when Number
          # TODO multiply the matrix by itself r times
          raise RuntimeError, 'Oh shi-'
          
        else
          raise MothsError, 'Exponentation undefined for these types'
      end
    end
  end
  
end